// serialtoolwidget.cpp
#include "serialtoolwidget.h"
#include "modbusscanner.h"

#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QMessageBox>
#include <QScrollBar>
#include <QDateTime>
#include <QSerialPortInfo>
#include <QStatusBar>
#include <QTextStream>
#include <QDir>
#include <QRandomGenerator>
#include <QModbusRtuSerialMaster>

///类的构造函数
SerialToolWidget::SerialToolWidget(DeviceMonitor *device_monitor_input,HistoryPage *history_page_intput,  QWidget *parent)
    : device_monitor(device_monitor_input),history_page(history_page_intput), QWidget(parent)
{

    QString firstLine;
    QFile data(QDir::currentPath()+"/settings/serial_port_settings.txt");
    if(data.open(QFile::ReadOnly))
    {
        char buffer[4096];
        //读取第一行
        data.readLine(buffer,sizeof(buffer));
        qint64 log_back=data.readLine(buffer,sizeof(buffer));
        //lambda函数，去除中间的空格符、制表符等字符
        auto remove_space= [](QStringList &stringlist)
        {
            int index_lambda=0;
            while(index_lambda!=stringlist.count())
            {
                //去除空项目
                if (stringlist[index_lambda].contains(' ')
                    ||stringlist[index_lambda].contains('\t')
                    ||stringlist[index_lambda].contains(' ')
                    // ||stringlist
                    ||stringlist[index_lambda].size()==0)
                {
                    stringlist.removeAt(index_lambda);
                }else if(stringlist[index_lambda].contains("\r\n"))
                {
                    stringlist[index_lambda].replace("\r\n","");
                }
                else
                {
                    index_lambda++;
                }
            }
        };
        while(log_back!=-1)
        {

            QString data_raw=QString::fromUtf8(buffer);
            //这一行的各元素的列表*****
            QStringList data_raw_var=data_raw.split("\t");
            remove_space(data_raw_var);
            settings_pair.insert(data_raw_var[0],data_raw_var[1]);
            qDebug()<<"0:"<<data_raw_var[0]<<"  1:"<<data_raw_var[1];
            // qDebug()<<QString(data_raw[4])<<QString(data_raw[6]);
            log_back=data.readLine(buffer,sizeof(buffer));
        }

    }
    poller=new ModbusPoller(this);
    serialPort = new QSerialPort(this);
    statTimer = new QTimer(this);

    //初始化UI
    initUI();
    //初始化连接（按钮的信号和槽的连接）
    // connect(serialPort, SIGNAL(readyRead()), this, SLOT(readData()));//使用readReady作为信号时，串口有数据，但该信号不触发，因此采用计时器周期读入数据
    initConnections();
    //初始化端口连接
    initPortConfig();
    Ensure_Path_Exits(QDir::currentPath()+"/Log",debug_data_save_location);
    Ensure_Path_Exits(QDir::currentPath()+"/Receive",receive_data_save_location);
    Ensure_Path_Exits(QDir::currentPath()+"/Receive_config",receive_config_location);
    Ensure_Path_Exits(QDir::currentPath()+"/Send_config",send_config_location);
    Update_Receive_Config();//刷新接收配置文件及对应的UI

    //开始计时（串口读入数据、更新显示）
    statTimer->start(100);
    setStyleSheet(R"(
        QWidget { font: 10pt "Segoe UI"; }
        QGroupBox {
            border: 1px solid #ccc;
            border-radius: 5px;
            margin-top: 1ex;
            padding-top: 12px;
        }
        QGroupBox::title {
            subcontrol-origin: margin;
            left: 10px;
            padding: 0 3px;
        }

        QPlainTextEdit, QComboBox {
            border: 1px solid #ccc;
            border-radius: 4px;
            padding: 4px;
        }
        QLabel#statusLabel { color: #666; font-style: italic; }
        #statusLabel {
            background: #f5f5f5;
            border-top: 1px solid #ddd;
            color: #666;
            padding: 4px;
            min-height: 24px;
        QPushButton {
            background: #4CAF50;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 4px;
            min-width: 10px;
        }
        QPushButton:hover { background: #45a049; }
        QPushButton:disabled { background: #cccccc; }
        }
    )");
    //UI相关控件已恢复设置
    re_connect();



}

///初始化UI及相关的控件
void SerialToolWidget::initUI()
{
    // Port Configuration
    QGroupBox *portGroup = new QGroupBox("串口配置");
    //btnRefreshPort = new QPushButton(QIcon(":/refresh.png"), "刷新端口列表"); // 可添加图标
    //btnRefreshPort->setToolTip("刷新端口列表");
    cbPort = new QComboBox;//端口
    cbBaud = new QComboBox;//波特率
    cbData = new QComboBox;//数据位
    cbParity = new QComboBox;//校验位
    cbStop = new QComboBox;//停止位
    btnOpenPort = new QPushButton("打开端口");
    btn_flushPort=new QPushButton("刷新端口");
    connect(this->btn_flushPort,SIGNAL(pressed()),this,SLOT(initPortConfig()));
    QHBoxLayout *portLayout = new QHBoxLayout;
    portLayout->addWidget(new QLabel("端口:"));
    portLayout->addWidget(cbPort);
    portLayout->addWidget(new QLabel("波特率:"));
    portLayout->addWidget(cbBaud);
    portLayout->addWidget(new QLabel("数据位:"));
    portLayout->addWidget(cbData);
    portLayout->addWidget(new QLabel("校验位:"));
    portLayout->addWidget(cbParity);
    portLayout->addWidget(new QLabel("停止位:"));
    portLayout->addWidget(cbStop);
    auto_reopen_port=new QCheckBox("自动打开上次连接的端口");
    portLayout->addWidget(auto_reopen_port);
    portLayout->addWidget(btnOpenPort);
    portLayout->addWidget(btn_flushPort);
    // portLayout->addWidget(btnRefreshPort);
    portGroup->setLayout(portLayout);


    cbBaud->addItems({"1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200"});
    for(int i=0;i<8;i++)
    {
        // qDebug()<<"index:"<<i<<"  "<<cbBaud->itemText(i)<<"   <==>"<<settings_pair["波特率"];
        if(cbBaud->itemText(i)==settings_pair["波特率"])
        {cbBaud->setCurrentIndex(i);qDebug()<<"数据被设置";}
    }//根据配置文件设置上次保存的数据
    // cbBaud->setCurrentIndex(3);//默认波特率为9600

    cbData->addItems({"5", "6", "7", "8"});
    for(int i=0;i<4;i++){if(cbData->itemText(i)==settings_pair["数据位"])cbData->setCurrentIndex(i);}//根据配置文件设置上次保存的数据
    /*
        ‌Odd（奇校验）‌：在奇校验中，校验位的设置是为了确保数据位中1的个数为奇数。如果数据位中1的个数是偶数，校验位为1；如果数据位中1的个数是奇数，校验位为0。例如，数据“1110000”中1的个数为3（奇数），但为了确保包含校验位后1的总数为奇数，校验位应为0，因此整体为“111000000”。如果数据“1111000”中1的个数为4（偶数），则校验位应为1，整体为“11110001”‌
        ‌Even（偶校验）‌：在偶校验中，校验位的设置是为了确保数据位中1的个数为偶数。如果数据位中1的个数是奇数，校验位为0；如果数据位中1的个数是偶数，校验位为1。例如，数据“1110000”中1的个数为3（奇数），校验位应为1，整体为“11100001”。如果数据“1111000”中1的个数为4（偶数），则校验位应为0，整体为“11110000”‌
        ‌Mark（标记）‌：在Mark校验中，校验位始终为1。这种校验方式主要用于某些特定的通信协议中，确保接收方能够识别数据的开始或结束‌
        ‌Space（空间）‌：在Space校验中，校验位始终为0。这种校验方式也用于某些特定的通信协议中，用于标识数据的特定部分‌
    */
    cbParity->addItems({"无", "偶校验", "奇校验", "MARK:1", "SPACE:0"});
    for(int i=0;i<4;i++){if(cbParity->itemText(i)==settings_pair["校验位"])cbParity->setCurrentIndex(i);}//根据配置文件设置上次保存的数据
    //停止位
    cbStop->addItems({"1", "1.5", "2"});
    for(int i=0;i<4;i++){if(cbStop->itemText(i)==settings_pair["停止位"])cbStop->setCurrentIndex(i);}//根据配置文件设置上次保存的数据

    bool temp= settings_pair["自动打开上次连接的端口"].toInt()?true:false;//非0为真
    auto_reopen_port->setChecked(temp);

    // 接收区
    QGroupBox *receiveGroup = new QGroupBox("数据接收");
    txtReceive = new QPlainTextEdit;
    // txtReceive->setMinimumSize(400, 200);
    chkHexDisplay = new QCheckBox("Hex显示");
    temp= settings_pair["Hex显示"].toInt()?true:false;//非0为真
    chkHexDisplay->setChecked(true);
    receive_save2db=new QCheckBox("自动保存到数据库");
    chkAutoReload = new QCheckBox("自动接收数据");
    start_data_simulate=new QCheckBox("开启数据模拟");
    connect(start_data_simulate,SIGNAL(stateChanged(int)),this,SLOT(auto_simulate_data(int)));
    temp= settings_pair["开启数据模拟"].toInt()?true:false;//非0为真
    start_data_simulate->setChecked(temp);
    temp= settings_pair["自动接收数据"].toInt()?true:false;
    chkAutoReload->setChecked(temp);
    temp= settings_pair["自动保存到数据库"].toInt()?true:false;
    receive_save2db->setChecked(temp);
    connect(this->chkAutoReload,SIGNAL(checkStateChanged(Qt::CheckState)),this,SLOT(auto_read_Data(Qt::CheckState)));
    // chk_Cycle_read=new QCheckBox("按周期接收数据");
    // chk_Cycle_read->setChecked(false);
    // connect(this->chk_Cycle_read,SIGNAL(checkStateChanged(Qt::CheckState)),this,SLOT(on_receive_by_cycle(Qt::CheckState)));
    receive_Log=new QCheckBox("记录已接收的数据到日志");
    temp= settings_pair["记录已接收的数据到日志"].toInt()?true:false;
    receive_Log->setChecked(temp);
    // chkTimestamp = new QCheckBox("时间戳");
    btnClearRx = new QPushButton("清空接收");

    QHBoxLayout *receiveCtrlLayout = new QHBoxLayout;
    receiveCtrlLayout->addStretch();
    receiveCtrlLayout->addWidget(start_data_simulate);
    receiveCtrlLayout->addWidget(chkHexDisplay);
    receiveCtrlLayout->addWidget(receive_save2db);
    receiveCtrlLayout->addWidget(chkAutoReload);
    receiveCtrlLayout->addWidget(receive_Log);
    receiveCtrlLayout->addWidget(btnClearRx);
    btn_Receive_save=new QPushButton("保存到文件");
    receiveCtrlLayout->addWidget(btn_Receive_save);
    connect(this->btn_Receive_save,SIGNAL(pressed()),this,SLOT(Save_Receive_Zone()));
    // receiveCtrlLayout->addWidget(chkTimestamp);


    QVBoxLayout *receiveLayout = new QVBoxLayout;
    receiveLayout->addWidget(txtReceive);
    receiveLayout->addLayout(receiveCtrlLayout);
    receiveGroup->setLayout(receiveLayout);

    // Send Area
    QGroupBox *sendGroup = new QGroupBox("读取操作配置");
    //发送区1
    QVBoxLayout *sendZone1=new QVBoxLayout;
    QHBoxLayout *sendTopLayout = new QHBoxLayout;
    //顶部标题
    //底部水平布局
    QHBoxLayout *send_Zone_Properties=new QHBoxLayout;
    send_Zone_Properties->addStretch();
    auto_resend_config_file=new QCheckBox("连接后自动重读");

    send_Zone_Properties->addWidget(auto_resend_config_file);
    temp= settings_pair["自动重发选中的配置文件的内容"].toInt()?true:false;
    qDebug()<<temp;
    auto_resend_config_file->setChecked(temp);
    connect(auto_resend_config_file,SIGNAL(checkStateChanged(Qt::CheckState)),this,SLOT(on_auto_send_config_file(Qt::CheckState)));
    temp= settings_pair["记录已发送的数据到日志"].toInt()?true:false;
    QLabel *send_cycle_text=new QLabel("循环周期：");
    send_Zone_Properties->addWidget(send_cycle_text);
    sb_cycle_edit=new QSpinBox;
    sb_cycle_edit->setMaximum(1000000);
    sb_cycle_edit->setMinimum(1);
    int temp_int_value=settings_pair["循环周期"].toInt();
    sb_cycle_edit->setValue(temp_int_value);

    send_Zone_Properties->addWidget(sb_cycle_edit);
    QLabel *send_cycle_ms=new QLabel("ms");
    send_Zone_Properties->addWidget(send_cycle_ms);
    btn_Auto_ReSend=new QPushButton("按照周期读取寄存器的数据");
    send_Zone_Properties->addWidget(btn_Auto_ReSend);
    connect(this->btn_Auto_ReSend,SIGNAL(pressed()),this,SLOT(onAutoReadClicked()));
    //发送区1的总体布局
    sendZone1->addLayout(sendTopLayout);
    sendZone1->addLayout(send_Zone_Properties);
    QVBoxLayout *sendLayout = new QVBoxLayout;
    sendLayout->addLayout(sendZone1);
    sendGroup->setLayout(sendLayout);

    // Statistics
    lblStats = new QLabel("接收: 0 字节 | 发送: 0 字节");
    lblStats->setAlignment(Qt::AlignRight);

    // // 发送区属性
    // QGroupBox *sendPropertiesGroup = new QGroupBox("数据发送区属性及文件轮发属性");


    //Debug区
    QGroupBox *Debug_group_box=new QGroupBox("消息日志");
    QHBoxLayout *Debug_hlayout=new QHBoxLayout;
    Debug_Zone=new QTextEdit;

    QPushButton *btn_clear_debug_zone=new QPushButton("清空消息日志区");
    connect(btn_clear_debug_zone,SIGNAL(pressed()),this,SLOT(Clear_Debug_Zone()));
    QPushButton *btn_save_debug_zone=new QPushButton("保存消息日志区到文件");
    connect(btn_save_debug_zone,SIGNAL(pressed()),this,SLOT(Save_Debug_Zone()));
    Debug_hlayout->addStretch();
    Debug_hlayout->addWidget(btn_clear_debug_zone);
    Debug_hlayout->addWidget(btn_save_debug_zone);

    QVBoxLayout *debug_layout_v1=new QVBoxLayout;
    debug_layout_v1->addWidget(Debug_Zone);
    debug_layout_v1->addLayout(Debug_hlayout);
    Debug_group_box->setLayout(debug_layout_v1);


    // 状态栏
    statusLabel = new QLabel;
    statusLabel->setObjectName("statusLabel");
    statusLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    // Main Layout
    QVBoxLayout *rightLayout = new QVBoxLayout(nullptr);
    QHBoxLayout *mainlayout=new QHBoxLayout(this);
    QVBoxLayout *config_layout=new QVBoxLayout(this);

    QVBoxLayout *receive_config_groupbox_layout=new QVBoxLayout;
    QVBoxLayout *send_config_groupbox_layout=new QVBoxLayout;
    receive_config_groupbox=new QGroupBox("接收区配置文件");
    send_config_groupbox=new QGroupBox("当前总线上的采集设备");
    receive_config_listwidget=new QListWidget(nullptr);
    send_config_listwidget=new QListWidget(nullptr);
    send_configitem_list=new QList<QListWidgetItem*>;
    receive_config_groupbox->setLayout(receive_config_groupbox_layout);
    send_config_groupbox->setLayout(send_config_groupbox_layout);
    receive_config_groupbox_layout->addWidget(receive_config_listwidget);
    send_config_groupbox_layout->addWidget(send_config_listwidget);
    config_layout->addWidget(receive_config_groupbox);
    config_layout->addWidget(send_config_groupbox);
    mainlayout->addLayout(config_layout,1);//比例占1
    mainlayout->addLayout(rightLayout,5);//比例占5

    rightLayout->addWidget(portGroup);
    rightLayout->addWidget(receiveGroup);
    rightLayout->addWidget(sendGroup);
    rightLayout->addWidget(Debug_group_box);//添加Debug栏
    rightLayout->addWidget(lblStats);
    rightLayout->addWidget(statusLabel); // 添加状态栏

}

///初始化连接
void SerialToolWidget::initConnections()
{

    connect(btnOpenPort, &QPushButton::clicked, this, &SerialToolWidget::onPortOpenClicked);
    connect(btnClearRx, &QPushButton::clicked, this, &SerialToolWidget::onClearRxClicked);
    connect(serialPort, &QSerialPort::errorOccurred, this, &SerialToolWidget::handleError);
    connect(statTimer, &QTimer::timeout, this, &SerialToolWidget::updateStatistics);
    connect(receive_config_listwidget, &QListWidget::itemDoubleClicked, [=](QListWidgetItem *item) {
        qDebug() << "双击的项内容:" << item->text();
    });
}

///刷新端口连接
void SerialToolWidget::initPortConfig()
{
    // 获取当前日期和时间
    QDateTime datetime = QDateTime::currentDateTime();
    QString customFormat = "yyyy-MM-dd HH:mm:ss"; // 年-月-日 时:分:秒
    cbPort->clear();
    Debug_Zone->append(datetime.toString(customFormat)+QString(" ")+"刷新连接的端口：");
    int portcount=0;
    //初始化可以读取的端口
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
        QSerialPort serial;
        serial.setPort(info);
        if(serial.open(QIODevice::ReadWrite))//尝试读取该端口
        {
            Debug_Zone->append(datetime.toString(customFormat)+QString(" ")+QString("成功读取端口：")+QString(info.portName()));
            portcount++;
            cbPort->addItem(serial.portName());//添加到端口栏
            serial.close();
        }
    }
    Debug_Zone->append(datetime.toString(customFormat)+QString(" ")+QString("可用的端口总计数目:")+QString::number(portcount));
}


///打开串口连接
void SerialToolWidget::onPortOpenClicked()
{

    Update_Send_Config();


    // 获取当前日期和时间
    QDateTime datetime = QDateTime::currentDateTime();
    QString customFormat = "yyyy-MM-dd HH:mm:ss"; // 年-月-日 时:分:秒

    //如果端口正打开则关闭
    if (poller->connected)
    {
        poller->disconnect_device();
        poller->connected=false;
        btnOpenPort->setText("打开端口");
        // setUiEnabled(true);
        showStatusMessage("端口已关闭");
        port_opened=false;
        Debug_Zone->append(datetime.toString(customFormat)+QString(" ")+cbPort->currentText()+"端口已关闭");
        btn_Auto_ReSend->click();
        return;
    }

    //设置串口名为当前选择项目的名字
    QVariant Port=cbPort->currentText();
    // 配置并打开串口的逻辑...
    QVariant BaudRate= cbBaud->currentText().toInt();//设置波特率
    QVariant DataBits;
    //通过索引设置数据位
    switch (cbData->currentIndex()) {
    case 0:
        DataBits=QSerialPort::Data5;
        break;
    case 1:
        DataBits=QSerialPort::Data6;
        break;
    case 2:
        DataBits=QSerialPort::Data7;
        break;
    case 3:
        DataBits=QSerialPort::Data8;
        break;
    }

    QVariant Parity;
    //通过索引值设置校验位
    switch (cbParity->currentIndex()) {
    case 0:
        Parity=QSerialPort::NoParity;
        break;
    case 1:
        Parity=QSerialPort::EvenParity;
        break;
    case 2:
        Parity=QSerialPort::OddParity;
        break;
    case 3:
        Parity=QSerialPort::MarkParity;
        break;
    case 4:
        Parity=QSerialPort::SpaceParity;
        break;
    }

    QVariant StopBits;
    //通过索引至设置停止位
    switch (cbStop->currentIndex()) {
    case 0:
        StopBits=QSerialPort::OneStop;
        break;
    case 1:
        StopBits= QSerialPort::OneAndHalfStop;
        break;
    case 2:
        StopBits=QSerialPort::TwoStop;
        break;
    }

    //配置端口相关信息
    poller->SetUpModbusRTU(Port,BaudRate,Parity,DataBits,StopBits,100);

    //尝试打开串口
    if (poller->connect_device()) {
        btnOpenPort->setText("关闭端口");
        setUiEnabled(false);
        showStatusMessage("端口已打开");
        port_opened = true;
        poller->connected=true;
        Debug_Zone->append(datetime.toString(customFormat)+QString(" ")+"成功建立与"+serialPort->portName()+"的连接！");
        // Debug_Zone->append("波特率:"+QString::number(serialPort->baudRate()));
        //刷新该串口的可用设备

    } else {
        showStatusMessage("打开失败：" + serialPort->errorString());
        port_opened = false;
        poller->connected=true;
        Debug_Zone->append(datetime.toString(customFormat)+QString(" ")+cbPort->currentText()+"打开失败：" + serialPort->errorString());
    }

}

///打开或关闭相关的UI
void SerialToolWidget::setUiEnabled(bool state)
{
    cbPort->setEnabled(state);
    cbBaud->setEnabled(state);
    cbData->setEnabled(state);
    cbParity->setEnabled(state);
    cbStop->setEnabled(state);
    btn_Auto_ReSend->setEnabled(!state);
}


///当自动重发按钮被按下时，触发按周期自动重发数据
void SerialToolWidget::onAutoReadClicked()
{
    // 获取当前日期和时间
    QDateTime datetime = QDateTime::currentDateTime();
    QString customFormat = "yyyy-MM-dd HH:mm:ss"; // 年-月-日 时:分:秒

    if(!port_opened)
    {
        Debug_Zone->append(datetime.toString(customFormat)+QString(" ")+QString("要启动自动重发，请先打开串口！"));
        return;
    }
    if(btn_Auto_ReSend->text()!="正在按周期读入寄存器中的数据...")//如果没有处在重发状态
    {
        poller->startPolling();
        btn_Auto_ReSend->setText("正在按周期读入寄存器中的数据...");
        Debug_Zone->append(datetime.toString(customFormat)+QString(" ")+QString("开始自动读取寄存器数据......"));
    }
    else//取消自动读取
    {
        poller->stopPolling();
        btn_Auto_ReSend->setText("按照周期读取寄存器的数据");
        Debug_Zone->append(datetime.toString(customFormat)+QString(" ")+QString("按周期读取寄存器数据已取消！"));
    }
}


///输出报错信息
void SerialToolWidget::handleError(QSerialPort::SerialPortError error)
{
    if (error == QSerialPort::NoError) return;
    showStatusMessage("错误: " + serialPort->errorString());
    Debug_Log("错误: " + serialPort->errorString());
}


///更新统计状态
void SerialToolWidget::updateStatistics()
{
    // lblStats->setText(QString("接收: %1 字节 | 发送: %2 字节")
    //                           .arg(bytesReceived).arg(bytesSent));
}

///显示当前的状态信息
void SerialToolWidget::showStatusMessage(const QString &message)
{
    statusLabel->setText(message);

    // 自动清除消息（3秒后）
    QTimer::singleShot(3000, [this](){
        if(statusLabel->text().startsWith("状态：")){
            statusLabel->clear();
        }
    });
}

///当接收区的清空按钮被按下（清空接收区的消息）
void SerialToolWidget::onClearRxClicked()
{
    txtReceive->clear();
    bytesReceived = 0;
    Debug_Log(" 接收数据区已清空！");
}

///保存接受区文本到文件
void SerialToolWidget::Save_Receive_Zone()
{
    QDateTime datetime = QDateTime::currentDateTime();
    QString customFormat = "yyyy-MM-dd   HH ：mm ：ss"; // 年-月-日 时:分:秒
    QString path=receive_data_save_location+"/接收数据"+datetime.toString(customFormat)+".txt";
    QFile data(path);
    if(data.open(QFile::WriteOnly))
    {
        QTextStream out(&data);
        QString temp=this->txtReceive->toPlainText();
        if(temp!="")out<<temp;
        Debug_Log(" 已保存接收文件到"+path);
    }
    data.close();
}

///清空日志区
void SerialToolWidget::Clear_Debug_Zone()
{
    this->Debug_Zone->clear();
}
///保存日志区
void SerialToolWidget::Save_Debug_Zone()
{
    QDateTime datetime = QDateTime::currentDateTime();
    QString customFormat = "yyyy-MM-dd   HH ：mm ：ss"; // 年-月-日 时:分:秒
    QString path=debug_data_save_location+"/消息日志"+datetime.toString(customFormat)+".txt";
    QFile data(path);
    if(data.open(QFile::WriteOnly))
    {
        QTextStream out(&data);
        out<<this->Debug_Zone->toPlainText();
        Debug_Log(" 已保存日志文件到"+path);
    }
    data.close();
}
///确保目目录存在
void SerialToolWidget::Ensure_Path_Exits(QString path,QString&var)
{
    QDir dir;
    if (!dir.exists(path)) { // 检查目录是否存在
        if (dir.mkdir(path)) { // 尝试创建目录
            qDebug() << "Directory created:" << path;
        } else {
            qDebug() << "Failed to create directory:" << path;
        }
    }
    var=path;
}

///析构函数
SerialToolWidget::~SerialToolWidget()
{


    //保存相关设置属性
    QString firstLine;
    QFile data(QDir::currentPath()+"/settings/serial_port_settings.txt");
    if(data.open(QFile::WriteOnly|QFile::Truncate))//Truncate覆盖型写入
    {
        QTextStream out(&data);
        out<<"占位行\t\t"<<"占位行"<<"\t"<<Qt::endl;
        out<<"自动打开上次连接的端口\t\t"<<auto_reopen_port->checkState()*0.5<<"\t"<<Qt::endl;
        out<<"上次连接的端口\t\t"<<serialPort->portName()<<"\t"<<Qt::endl;
        out<<"波特率\t\t"<<cbBaud->currentText()<<"\t"<<Qt::endl;
        out<<"数据位\t\t"<<cbData->currentText()<<"\t"<<Qt::endl;
        out<<"校验位\t\t"<<cbParity->currentText()<<"\t"<<Qt::endl;
        out<<"停止位\t\t"<<cbStop->currentText()<<"\t"<<Qt::endl;

        //接收区
        out<<"开启数据模拟\t\t"<<start_data_simulate->checkState()*0.5<<"\t"<<Qt::endl;
        out<<"接收Hex显示\t\t"<<chkHexDisplay->checkState()*0.5<<"\t"<<Qt::endl;
        out<<"自动接收数据\t\t"<<chkAutoReload->checkState()*0.5<<"\t"<<Qt::endl;
        out<<"记录已接收的数据到日志\t\t"<<receive_Log->checkState()*0.5<<"\t"<<Qt::endl;
        out<<"自动保存到数据库\t\t"<<receive_save2db->checkState()*0.5<<"\t"<<Qt::endl;
        //发送区
        out<<"自动重发选中的配置文件的内容\t\t"<<auto_resend_config_file->checkState()*0.5<<"\t"<<Qt::endl;
        out<<"循环周期\t\t"<<sb_cycle_edit->value()<<"\t"<<Qt::endl;


        //保存发送配置文件名
        QString str_temp;
        for(int i=0;i<send_configitem_list->count();i++)
        {
            if(send_configitem_list->value(i)->checkState()==Qt::Checked)str_temp+=send_configitem_list->value(i)->text()+",";
        }
        str_temp.removeAt(str_temp.size()-1);
        qDebug()<<"保存的发送区配置"<<str_temp;
        out<<"发送区选中配置文件\t\t"<<str_temp<<"\t"<<Qt::endl;
    }
    serialPort->close();
    qDebug()<<"已关闭串口连接";
}

///输出指定字符串到日志区
void SerialToolWidget::Debug_Log(QString s)
{
    QDateTime datetime = QDateTime::currentDateTime();
    QString customFormat = "yyyy-MM-dd   HH ：mm ：ss\t"; // 年-月-日 时:分:秒
    Debug_Zone->append(datetime.toString(customFormat)+s);
}

///刷新UI接收的配置文件,并重新初始化实时数据显示区的树形结构和其对应的stackwidget
void SerialToolWidget::Update_Receive_Config()
{
    receive_processor_list=new QList<Receive_Processor*>;
    this->receive_config_listwidget->clear();
    QDir dir(receive_config_location);
    QStringList fileNames=dir.entryList(QDir::Files|QDir::NoDotAndDotDot);
    foreach(QString file_name, fileNames)
    {
        this->receive_config_listwidget->addItem(file_name);
        //解析
        receive_processor_list->push_back(Receive_Config(file_name));
    }

    //根据处理器列表重新初始化实时数据显示区
    if(this->device_monitor!=nullptr)
    {
        qDebug()<<"初始化实时数据显示区";
        this->device_monitor->update_construct(receive_processor_list);
    }
    else
    {
        qDebug()<<"serialtoolwidget->device_monitor 串口的实时处理子指针为空";
    }

    //根据处理器列表重新初始化历史查询页面
    if(this->history_page!=nullptr)
    {
        qDebug()<<"初始化历史页面查询页面";
        this->history_page->setupUI(receive_processor_list);
    }
    else
    {
        qDebug()<<"串口的历史查询页面为空";
    }

    poller->receive_processor_list=receive_processor_list;
    poller->history_page=history_page;
    poller->device_monitor=device_monitor;
}

///解析接受区的单个配置文件
Receive_Processor* SerialToolWidget::Receive_Config(QString &file_name)
{
        Debug_Log("读取接收配置文件"+file_name);
        qDebug()<<"读取接收配置文件"<<file_name;
        QString firstLine;
        QFile data(receive_config_location+"/"+ file_name);
        if(data.open(QFile::ReadOnly))
        {
            char buffer[4096];
            //读取第一行
            data.readLine(buffer,sizeof(buffer));
            QString title=QString(buffer);
            Debug_Log(title);
            QStringList list_title_name=title.split("\t");
            //lambda函数，去除中间的空格符、制表符等字符
            auto remove_space= [](QStringList &stringlist)
            {
                int index_lambda=0;
                while(index_lambda!=stringlist.count())
                {
                    //去除空项目
                    if (stringlist[index_lambda].contains(' ')
                        ||stringlist[index_lambda].contains('\t')
                        ||stringlist[index_lambda].contains(' ')
                        // ||stringlist
                        ||stringlist[index_lambda].size()==0)
                    {
                        stringlist.removeAt(index_lambda);
                    }else if(stringlist[index_lambda].contains("\r\n"))
                    {
                        stringlist[index_lambda].replace("\r\n","");
                    }
                    else
                    {
                        index_lambda++;
                    }
                }
            };
            //去除该行所有的空白
            remove_space(list_title_name);
            //尝试读取该文件
            qint64 log_back=data.readLine(buffer,sizeof(buffer));
            //保存各行的信息
            //字节位置
            QList<QList<int> *> *all_register_location=new QList<QList<int> *>;
            //编码方式
            QList<QString> *code_type=new QList<QString>;
            //变量的系数
            QList<double> *coefficient_list=new QList<double>;
            //单位
            QList<QString> *unit_list=new QList<QString>;
            //变量名（参数注解）
            QList<QString> *annotation_list=new QList<QString>;
            //数据库参数类型
            QList<QString> *db_var_type_list=new QList<QString>;

            //数据的表的参数名
            QList<QString> *param_db_name=new QList<QString>;
            //能耗参数的阈值
            QList<double> *param_top_value=new QList<double>;

            while(log_back!=-1)//若读取失败，则返回-1
            {
                qDebug()<<"=======================================================";
                //从buffer中获取原数据
                //data_raw为该行的原数据
                QString data_raw=QString::fromUtf8(buffer);
                qDebug()<<"行数据:"<<data_raw;
                if(data_raw.size()<20)break;
                //这一行的各元素的列表*****
                QStringList data_raw_var=data_raw.split("\t");
                remove_space(data_raw_var);//去除不需要的空元素
                // foreach(auto s,data_raw_var){qDebug()<<s;}
                // Debug_Log(QString::number(data_raw_var.count()));
                //第一个元素是位置
                QStringList bytes_location_temp=data_raw_var[0].split('_');//1_2->"1","2"
                qDebug()<<data_raw_var[0];
                //各参数由哪些寄存器所表示
                QList<int> *Rigister_location_Sub=new QList<int>;//1,2
                foreach(QString byte_location,bytes_location_temp)
                {
                    Rigister_location_Sub->push_back(byte_location.toInt());
                }
                //保存该行的字节的位置信息到列表中
                all_register_location->push_back(Rigister_location_Sub);
                //保存该行的各数据
                code_type->push_back(data_raw_var[1]);
                qDebug()<<data_raw_var[1];
                //插入数据的单位
                coefficient_list->push_back(data_raw_var[2].toDouble());
                qDebug()<<data_raw_var[2];
                //插入数据的单位
                unit_list->push_back(data_raw_var[3]);
                qDebug()<<data_raw_var[3];
                //参入参数的解释名称（一般为其中文名）
                annotation_list->push_back(data_raw_var[4]);
                qDebug()<<data_raw_var[4];
                //插入参数在数据库中的类型
                db_var_type_list->push_back(data_raw_var[5]);
                qDebug()<<data_raw_var[5];
                //插入数据的在数据库中的参数名
                param_db_name->push_back(data_raw_var[6]);
                qDebug()<<data_raw_var[6];
                //插入能耗参数的阈值
                param_top_value->push_back(data_raw_var[7].toDouble());
                qDebug()<<data_raw_var[7];
                // qDebug()<<data_raw_var[4]+" : "<<QString(data_raw_var[7]);
                log_back=data.readLine(buffer,sizeof(buffer));
            }
            qDebug()<<"test_point";
            if(file_name.contains(".txt"))
            {
                file_name=file_name.replace(".txt","");
            }
            QStringList sep_list= file_name.split('_');
            qDebug()<<"test_point";
            Receive_Processor *processor_temp=new Receive_Processor(all_register_location,
                                                                      code_type,
                                                                      coefficient_list,
                                                                      unit_list,
                                                                      annotation_list,
                                                                      db_var_type_list,
                                                                      param_db_name,
                                                                      param_top_value,
                                                                      sep_list[0]);//address地址码（十六进制）)

            return processor_temp;

        }
        else{
            Debug_Log("未能成功读取未配置文件:"+file_name);
            return nullptr;
        }
}

///刷新发送配置文件及其对应的UI
void SerialToolWidget::Update_Send_Config()
{
    ModbusScanner scanner;
    scanner.startScan();


    // QString temp=settings_pair["发送区选中配置文件"];
    this->send_config_listwidget->clear();
    // for(int address=1;address<active_devices.count()+1;address++)
    // {
    //     QListWidgetItem *item=new QListWidgetItem(QString::number(address));
    //     this->send_config_listwidget->addItem(item);
    //     // 读取是否应该自动写入到发送区
    //     send_configitem_list->push_back(item);
    //     if(active_devices.contains(address))
    //     {
    //         item->setCheckState(Qt::Checked);
    //     }
    //     else
    //     {
    //         item->setCheckState(Qt::Unchecked);
    //     }
    // }

}

///开始自动生成数据
void SerialToolWidget::auto_simulate_data(int checked_state)
{
    if(checked_state==Qt::Unchecked)//未选中自动生成数据
    {
        if(data_simulate_timer!=nullptr)
        {
            data_simulate_timer->stop();
        }

    }
    else if(checked_state==Qt::Checked)//选中了自动生成数据
    {
        data_simulate_timer=new QTimer;
        data_simulate_timer->start(1000);
        connect(data_simulate_timer,SIGNAL(timeout()),this,SLOT(Data_Process()));
    }

}

void SerialToolWidget::re_connect()
{
    //尝试重新连接
    if(auto_reopen_port->checkState()==Qt::Checked&&settings_pair["自动打开上次连接的端口"]!="")
    {
        //尝试重连上次的连接
        onPortOpenClicked();
        Debug_Log("端口恢复连接成功");
    }
    auto_resend_config_file_timer=new QTimer;
    connect(auto_resend_config_file_timer,SIGNAL(timeout()),this,SLOT(send_temp_function()));
    auto_resend_config_file_timer->start(sb_cycle_edit->value());//根据循环周期的值来进行重复检测
    //尝试根据发送配置文件周期性发送数据
    // send_temp_function();
}
